package com.myzl.quartz.task;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.myzl.coal.domain.AlarmEvent;
import com.myzl.coal.domain.Device;
import com.myzl.coal.domain.Rfid;
import com.myzl.coal.domain.ThresholdData;
import com.myzl.coal.mq.MqService;
import com.myzl.coal.service.*;
import com.myzl.coal.utils.CalculationUtils;
import com.myzl.common.enums.*;
import com.myzl.common.utils.StringUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 告警任务
 *
 * @author Administrator
 * @date 2022年12月29日09:49:54
 */
@Component("alarmTask")
@Slf4j
@Data
public class AlarmTask {

    private final IDeviceService deviceService;
    private final IDemoService demoService;
    private final IRfidService rfidService;
    private final IRealTimeDataService realTimeDataService;
    private final IThresholdDataService thresholdDataService;
    private final IAlarmEventService alarmEventService;
    private final MqService mqService;

    public void deviceExceptionAlarm() {
        List<Device> devices = deviceService.getDeviceByGroup(DeviceGroupEnum.SIEVE.getCode(), DeviceTypeEnum.LIDAR.getCode());
        List<AlarmEvent> alarmEventAddList = new ArrayList<>();
        List<AlarmEvent> alarmEventUpdateList = new ArrayList<>();

        for (Device device : devices) {
            if (Objects.equals(DeviceStatusEnum.OFFLINE.getCode(), device.getDeviceStatus())) {
                continue;
            }
            Map<Integer, String> thicknessData = realTimeDataService.thicknessAlarmData(device.getId());
            if (thicknessData.isEmpty()) {
                continue;
            }
            List<ThresholdData> thresholdByDevice = thresholdDataService.getThresholdByDevice(device);

            handleAlarm(alarmEventAddList, alarmEventUpdateList, device, thicknessData, thresholdByDevice);
        }
        if (!alarmEventAddList.isEmpty()) {
            mqService.sendPolice(alarmEventAddList);
        }
        if (!alarmEventUpdateList.isEmpty()) {
            alarmEventService.updateBatchById(alarmEventUpdateList);
        }
    }

    private void handleAlarm(List<AlarmEvent> alarmEventAddList, List<AlarmEvent> alarmEventUpdateList, Device device, Map<Integer, String> thicknessData, List<ThresholdData> thresholdByDevice) {
        for (ThresholdData rule : thresholdByDevice) {
            Map<String, String> alarmText = thresholdDataService.getAlarmText(rule);
            BigDecimal data = null;
            if (Objects.equals(SieveRadarCommandEnum.UNBALANCE_ALARM.getCode(), rule.getDictValue())) {
                String leftData = thicknessData.get(SieveRadarCommandEnum.LEFT_AVERAGE_THICKNESS.getCode());
                String middleData = thicknessData.get(SieveRadarCommandEnum.MIDDLE_AVERAGE_THICKNESS.getCode());
                String rightData = thicknessData.get(SieveRadarCommandEnum.RIGHT_AVERAGE_THICKNESS.getCode());
                data = CalculationUtils.differenceValue(new BigDecimal(leftData), new BigDecimal(middleData), new BigDecimal(rightData));
            } else if (Integer.valueOf(SieveRadarCommandEnum.COAL_BIG_ALARM.getCode()).equals(rule.getDictValue())) {
                String thickness = thicknessData.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode());
                data = new BigDecimal(thickness);
            } else if (Integer.valueOf(SieveRadarCommandEnum.COAL_SMALL_ALARM.getCode()).equals(rule.getDictValue())) {
                String thickness = thicknessData.get(SieveRadarCommandEnum.ALL_AVERAGE_THICKNESS.getCode());
                data = new BigDecimal(thickness);
            }
            if (ObjectUtils.isNotNull(data)) {
                AlarmEvent alarmEvent = thresholdDataService.compareTo(device.getId(), data, alarmText.get("title"), alarmText.get("content") + data, true, rule);
                if (StringUtils.isNotNull(alarmEvent)) {
                    AlarmEvent oldAlarmEvent = alarmEventService.getOne(new LambdaUpdateWrapper<AlarmEvent>()
                            .eq(AlarmEvent::getDeviceId, alarmEvent.getDeviceId())
                            .eq(AlarmEvent::getThresholdDataId, alarmEvent.getThresholdDataId())
                            .eq(AlarmEvent::getHandleStatus, HandleStatusEnum.UNHANDLED.getCode())
                            .last("limit 1"));
                    if (ObjectUtils.isNull(oldAlarmEvent)) {
                        alarmEventAddList.add(alarmEvent);
                    } else {
                        LocalDateTime happenTime = LocalDateTimeUtil.of(oldAlarmEvent.getUpdateTime());
                        LocalDateTime levelTime = happenTime.plusHours(rule.getLevelInterval());
                        if (levelTime.isBefore(LocalDateTime.now())) {
                            oldAlarmEvent.setUpdateTime(null);
                            oldAlarmEvent.setEventLevel(AlarmLevel.getNextCode(oldAlarmEvent.getEventLevel()));
                            alarmEventUpdateList.add(oldAlarmEvent);
                        }
                    }
                    int count = alarmEventService.count(new LambdaUpdateWrapper<AlarmEvent>()
                            .eq(AlarmEvent::getDeviceId, alarmEvent.getDeviceId())
                            .eq(AlarmEvent::getHandleStatus, HandleStatusEnum.UNHANDLED.getCode())
                            .last("limit 1"));
                    if (count > 0) {
                        realTimeDataService.updateRealTimeDeviceStatus(device.getId(), StatusStringType.YES);
                    }
                }
            }
        }
    }

    public void rfidAlarm() {

        Device deviceParams = new Device();
        deviceParams.setDeviceType(DeviceTypeEnum.SIEVE_PLAT.getCode());
        List<Device> devices = deviceService.selectDeviceList(deviceParams);
        devices.forEach(e->{
            JSONObject deviceConfigJSONObject = e.getDeviceConfigJSONObject();
            boolean isOverhaul = deviceConfigJSONObject.getBooleanValue(DeviceConfigEnum.IS_OVERHAUL.getCode());
            if (isOverhaul){
                return;
            }
            Integer offLineTime = deviceConfigJSONObject.getInteger(DeviceConfigEnum.OFF_LINE_TIME.getCode());
            Rfid rfid = new Rfid();
            DateTime offLineDateTime = DateUtil.offsetSecond(new Date(), -offLineTime);
            rfid.setOffLineTime(offLineDateTime);

            List<Rfid> onlineList = rfidService.selectOnline(rfid);
            List<Rfid> offlineList = rfidService.selectOffline(rfid);

            if (!onlineList.isEmpty()) {
                alarmEventService.rfidRestore(onlineList);
            }

            if (!offlineList.isEmpty()) {
                alarmEventService.rfidPolice(offlineList);
            }
        });


    }

}
